package com.info.zhiduoduo.common.utils;

import org.springframework.web.bind.annotation.RequestBody;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class ReflectionUtil {

	/**
	 * 如果c是包装类，将它转换成基本类型，如果不是包装类，则不变。
	 *
	 * @param c 类对象
	 * @return
	 */
	public static Class transferToPrime(Class c) {

		Field[] fields = c.getDeclaredFields();
		for (int i = 0; i < fields.length; i++) {

			if (fields[i].getName().equals("TYPE")) {
				try {
					return (Class) fields[i].get(null);
				} catch (Exception ignored) {
				}
			}
		}
		return c;

	}

	/**
	 * 判断是否是基本类型，如果是包装类，同样会判断成基本类型
	 *
	 * @param clazz
	 * @return
	 */
	public static boolean isPrimitive(Class clazz) {
		return transferToPrime(clazz).isPrimitive();
	}

	/**
	 * 判断是否是数字类型的，包括 short，int，long，float，double 及他们的包装类
	 *
	 * @param clazz
	 * @return
	 */
	public static boolean isNumerical(Class clazz) {
		Class c = transferToPrime(clazz);
		return c == short.class || c == int.class || c == long.class || c == float.class || c == double.class;
	}

	/**
	 * 判断类是否是基本类型或字符串。如果是包装类，同样会判断成基本类型
	 *
	 * @param clazz
	 * @return
	 */
	public static boolean isPrimitiveOrString(Class clazz) {
		Class aClass = transferToPrime(clazz);
		return aClass.isPrimitive() || aClass.equals(String.class);
	}

	/**
	 * 通过反射获取标记了@RequestBody的请求参数类对象
	 */
	public static Parameter getRequestBody(Method method) {
		if (method == null) return null;

		Parameter[] parameters = method.getParameters();
		if (parameters == null) return null;

		for (Parameter parameter : parameters) {
			RequestBody annotation = parameter.getAnnotation(RequestBody.class);
			if (annotation != null) {
				return parameter;
			}
		}
		return null;
	}

	public static Object findRequestBody(Object[] args, Parameter[] parameters) {
		// 找到RequestBody
		if (parameters != null && parameters.length > 0) {
			for (int i = 0; i < parameters.length; i++) {
				Parameter parameter = parameters[i];
				if (parameter.isAnnotationPresent(RequestBody.class)) {
					return args[i];
				}
			}
		}
		return null;
	}

	/**
	 * 判断类是否含有指定的属性
	 *
	 * @param clazz
	 * @param field
	 * @return
	 */
	public static boolean hasField(Class clazz, String field) {
		try {
			Field clazzDeclaredField = clazz.getDeclaredField(field);
			return clazzDeclaredField != null;
		} catch (NoSuchFieldException e) {
			return false;
		}
	}

	/**
	 * 从对象实例中获取指定属性的值
	 *
	 * @param o
	 * @param filed
	 * @return
	 */
	public static Object getValue(Object o, String filed) {
		if (o == null) return null;

		try {
			Field field = o.getClass().getDeclaredField(filed);
			field.setAccessible(true);

			return field.get(o);
		} catch (Exception e) {
			return null;
		}
	}

	public static void main(String[] args) {
		String s = "ss";
		Integer i = 1;
		System.out.println(isPrimitiveOrString(s.getClass()));

	}

	public static <T extends Enum> String getEnum(Class<T> enumClazz, int code) {
		if (enumClazz.isEnum()) {
			try {
				Method method = enumClazz.getMethod("values");
				T t[] = (T[]) method.invoke(null);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return null;
	}

	/**
	 * 在类里找到所有被指定注解标注的方法列表
	 *
	 * @param clazz     目标类
	 * @param annoClazz 方法上指定的注解
	 * @return 方法列表
	 */
	public static List<Method> findAllMethodsWithAnnotation(Class<?> clazz, Class<? extends Annotation> annoClazz) {
		return Stream.of(clazz.getMethods()).filter(m -> m.isAnnotationPresent(annoClazz)).collect(Collectors.toList());
	}

	/**
	 * 判断实体类对象的全部属性是否空，为空返回false (如果持久层用的 MyBatis-Plus 框架，这时候需要判断的实力类对象中加入 serialVersionUID 全局参数)
	 * @param object
	 * @return
	 */
	public static boolean checkObjAllFieldsIsNull(Object object) {
		// 如果对象为null直接返回true
		if (null == object) {
			return true;
		}
		try {
			// 挨个获取对象属性值
			for (Field f : object.getClass().getDeclaredFields()) {
				f.setAccessible(true);
				// 如果有一个属性值不为null，且值不是空字符串，就返回false
				if (!"serialVersionUID".equals(f.getName()) && f.get(object) != null) {
					return false;
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return true;
	}
}
